import UIKit

protocol ImageCropViewControllerDelegate: AnyObject {
    func imageCropViewController(_ controller: ImageCropViewController, didFinishCroppingImage image: UIImage)
}

class ImageCropViewController: YDBBaseViewController {
    
    // MARK: - Properties
    
    weak var delegate: ImageCropViewControllerDelegate?
    // 配置属性
    var cropRatio: CGSize = CGSize(width: 1, height: 1)
    var cropBoxInsets: UIEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: kTabBarHeight, right: 20)
    
    // 视图
    private var scrollView: UIScrollView!
    private var imageView: UIImageView!
    private var overlayView: OverlayView!
    
    // 状态
    private var originalImage: UIImage!
    private var currentImage: UIImage!
    private var currentAngle: CGFloat = 0
    private var isHorizontallyFlipped = false
    private var isVerticallyFlipped = false
    
    // 裁剪框
    private var cropBoxFrame: CGRect = .zero
    
    // MARK: - Initialization
    
    init(image: UIImage, cropRatio: CGSize = CGSize(width: 1, height: 1)) {
        super.init()
        self.originalImage = image
        self.currentImage = image
        self.cropRatio = cropRatio
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - Lifecycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
        setupGestures()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        updateCropBoxFrame()
        updateMinZoomScale()
        adjustContentOffsetToValidArea()
    }
    
    // MARK: - UI Setup
    
    private func setupUI() {
        self.navigationItem.title = "cropping".localized
        view.backgroundColor = HexRGB(0x666666)
        self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(title: "confirm".localized, style: .done, target: self, action: #selector(done))
        setupScrollView()
        setupImageView()
        setupOverlayView()
        setupToolbar()
    }
    
    private func setupScrollView() {
        scrollView = UIScrollView()
        scrollView.delegate = self
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.showsVerticalScrollIndicator = false
//        scrollView.decelerationRate = .fast
        scrollView.bounces = true
        scrollView.bouncesZoom = true
        scrollView.alwaysBounceVertical = true
        scrollView.alwaysBounceHorizontal = true
        scrollView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(scrollView)
        
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -kTabBarHeight)
        ])
    }
    
    private func setupImageView() {
        imageView = UIImageView(image: currentImage)
        imageView.contentMode = .scaleAspectFit
        scrollView.addSubview(imageView)
    }
    
    private func setupOverlayView() {
        overlayView = OverlayView()
        overlayView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(overlayView)
        
        NSLayoutConstraint.activate([
            overlayView.topAnchor.constraint(equalTo: scrollView.topAnchor),
            overlayView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
            overlayView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
            overlayView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor)
        ])
    }
    
    private func setupToolbar() {
        let toolbar = UIView()
        toolbar.backgroundColor = .black
        toolbar.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(toolbar)
        
        NSLayoutConstraint.activate([
            toolbar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            toolbar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            toolbar.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            toolbar.heightAnchor.constraint(equalToConstant:kTabBarHeight)
        ])
        let btn1 =  UIButton.init(type: .custom)
        btn1.frame = CGRect(x: 0, y: 0, width: kScreenWidth/5, height: 44)
        btn1.setImage(UIImage(named: "rotateLeft"), for: .normal)
        btn1.addTarget(self, action: #selector(rotateLeft), for: .touchUpInside)
        toolbar.addSubview(btn1)
        let btn2 =  UIButton.init(type: .custom)
        btn2.frame = CGRect(x:kScreenWidth/5, y: 0, width: kScreenWidth/5, height: 44)
        btn2.setImage(UIImage(named: "rotateRight"), for: .normal)
        btn2.addTarget(self, action: #selector(rotateRight), for: .touchUpInside)
        toolbar.addSubview(btn2)
        
        let btn3 =  UIButton.init(type: .custom)
        btn3.frame = CGRect(x: kScreenWidth*2/5, y: 0, width: kScreenWidth/5, height: 44)
        btn3.setImage(UIImage(named: "flipHorizontal"), for: .normal)
        btn3.addTarget(self, action: #selector(flipHorizontal), for: .touchUpInside)
        toolbar.addSubview(btn3)
        
        let btn4 =  UIButton.init(type: .custom)
        btn4.frame = CGRect(x: kScreenWidth*3/5, y: 0, width: kScreenWidth/5, height: 44)
        btn4.setImage(UIImage(named: "flipVertical"), for: .normal)
        btn4.addTarget(self, action: #selector(flipVertical), for: .touchUpInside)
        toolbar.addSubview(btn4)
        
        let btn5 =  UIButton.init(type: .custom)
        btn5.frame = CGRect(x: kScreenWidth*4/5, y: 0, width: kScreenWidth/5, height: 44)
        btn5.setImage(UIImage(named: "reset"), for: .normal)
        btn5.addTarget(self, action: #selector(resetCrop), for: .touchUpInside)
        toolbar.addSubview(btn5)
    }
    // MARK: - Gestures
    private func setupGestures() {
        let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:)))
        doubleTapGesture.numberOfTapsRequired = 2
        scrollView.addGestureRecognizer(doubleTapGesture)
    }
    @objc private func handleDoubleTap(_ gesture: UITapGestureRecognizer) {
        if scrollView.zoomScale > scrollView.minimumZoomScale {
            scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
        } else {
            let point = gesture.location(in: imageView)
            let zoomRect = zoomRectForScale(scrollView.maximumZoomScale, center: point)
            scrollView.zoom(to: zoomRect, animated: true)
        }
    }
    // MARK: - Crop Box Management
    private func updateCropBoxFrame() {
        let availableSize = CGSize(
            width: view.bounds.width - cropBoxInsets.left - cropBoxInsets.right,
            height: scrollView.bounds.height - cropBoxInsets.top - cropBoxInsets.bottom
        )
        
        var cropSize: CGSize
        if cropRatio.width / cropRatio.height > availableSize.width / availableSize.height {
            cropSize = CGSize(width: availableSize.width, height: availableSize.width * cropRatio.height / cropRatio.width)
        } else {
            cropSize = CGSize(width: availableSize.height * cropRatio.width / cropRatio.height, height: availableSize.height)
        }
        
        cropBoxFrame = CGRect(
            x: (view.bounds.width - cropSize.width) / 2,
            y: cropBoxInsets.top + (scrollView.bounds.height - cropBoxInsets.top - cropBoxInsets.bottom - cropSize.height) / 2,
            width: cropSize.width,
            height: cropSize.height
        )
        
        overlayView.cropBoxFrame = cropBoxFrame
        
        // 更新scrollView的contentInset来匹配裁剪框
        scrollView.contentInset = UIEdgeInsets(
            top: cropBoxFrame.minY,
            left: cropBoxFrame.minX,
            bottom: scrollView.bounds.height - cropBoxFrame.maxY,
            right: view.bounds.width - cropBoxFrame.maxX
        )
    }
    
    // MARK: - Zoom Management
    
    private func updateMinZoomScale() {
        let cropBoxSize = cropBoxFrame.size
        let imageSize = currentImage.size
        
        let widthScale = cropBoxSize.width / imageSize.width
        let heightScale = cropBoxSize.height / imageSize.height
        
        // 最小缩放比例要确保图片能够完全覆盖裁剪框
        let minScale = max(widthScale, heightScale)
        
        scrollView.minimumZoomScale = minScale
        scrollView.maximumZoomScale = minScale * 4
        
        if scrollView.zoomScale < minScale {
            scrollView.zoomScale = minScale
        }
        
        // 更新imageView的frame和contentSize
        updateImageViewFrameAndContentSize()
    }
    
    private func updateImageViewFrameAndContentSize() {
        let imageSize = currentImage.size
        let zoomScale = scrollView.zoomScale
        
        imageView.frame = CGRect(
            x: 0,
            y: 0,
            width: imageSize.width * zoomScale,
            height: imageSize.height * zoomScale
        )
        
        scrollView.contentSize = imageView.frame.size
    }
    
    private func zoomRectForScale(_ scale: CGFloat, center: CGPoint) -> CGRect {
        var zoomRect = CGRect.zero
        zoomRect.size.height = imageView.frame.size.height / scale
        zoomRect.size.width = imageView.frame.size.width / scale
        zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0)
        zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0)
        return zoomRect
    }
    
    // MARK: - Transformations
    
    @objc private func rotateLeft() {
        rotate(by: -90)
    }
    
    @objc private func rotateRight() {
        rotate(by: 90)
    }
    
    private func rotate(by degrees: CGFloat) {
        guard let rotatedImage = currentImage.rotated(by: degrees) else { return }
        
        // 保存当前的缩放比例和偏移量
        let previousZoomScale = scrollView.zoomScale
        let previousContentOffset = scrollView.contentOffset
        
        currentImage = rotatedImage
        imageView.image = currentImage
        
        // 更新角度状态
        currentAngle += degrees
        while currentAngle < 0 { currentAngle += 360 }
        while currentAngle >= 360 { currentAngle -= 360 }
        
        // 更新图片尺寸和缩放比例
        updateMinZoomScale()
        
        // 计算新的contentOffset以保持图片在视图中的相对位置
        let newContentSize = scrollView.contentSize
        let scaleRatio = newContentSize.width / (currentImage.size.width * previousZoomScale)
        
        let newContentOffset = CGPoint(
            x: previousContentOffset.x * scaleRatio,
            y: previousContentOffset.y * scaleRatio
        )
        
        scrollView.contentOffset = newContentOffset
        
        // 确保不超出边界
        adjustContentOffsetToValidArea()
    }
    
    @objc private func flipHorizontal() {
        guard let flippedImage = currentImage.flippedHorizontally() else { return }
        
        currentImage = flippedImage
        imageView.image = currentImage
        isHorizontallyFlipped.toggle()
        
        updateImageViewFrameAndContentSize()
        adjustContentOffsetToValidArea()
    }
    
    @objc private func flipVertical() {
        guard let flippedImage = currentImage.flippedVertically() else { return }
        
        currentImage = flippedImage
        imageView.image = currentImage
        isVerticallyFlipped.toggle()
        
        updateImageViewFrameAndContentSize()
        adjustContentOffsetToValidArea()
    }
    
    @objc private func resetCrop() {
        currentImage = originalImage
        imageView.image = currentImage
        currentAngle = 0
        isHorizontallyFlipped = false
        isVerticallyFlipped = false
        
        UIView.animate(withDuration: 0.3) {
            self.scrollView.zoomScale = self.scrollView.minimumZoomScale
            self.adjustContentOffsetToValidArea()
        }
    }
    
    // MARK: - Content Offset Management
    
    private func adjustContentOffsetToValidArea() {
        let contentInset = scrollView.contentInset
        let contentSize = scrollView.contentSize
        let boundsSize = scrollView.bounds.size
        var contentOffset = scrollView.contentOffset
        
        // 计算有效的内容区域
        let minContentOffsetX = -contentInset.left
        let maxContentOffsetX = max(minContentOffsetX, contentSize.width - boundsSize.width + contentInset.right)
        let minContentOffsetY = -contentInset.top
        let maxContentOffsetY = max(minContentOffsetY, contentSize.height - boundsSize.height + contentInset.bottom)
        
        // 限制在有效范围内
        contentOffset.x = max(minContentOffsetX, min(contentOffset.x, maxContentOffsetX))
        contentOffset.y = max(minContentOffsetY, min(contentOffset.y, maxContentOffsetY))
        
        scrollView.contentOffset = contentOffset
    }
    // MARK: - Actions
    @objc private func done() {
        guard let croppedImage = cropImage() else { return }
        delegate?.imageCropViewController(self, didFinishCroppingImage: croppedImage)
        self.navigationController?.popViewController(animated: true)
    }
    private func cropImage() -> UIImage? {
        let zoomScale = scrollView.zoomScale
        
        // 计算在原始图片坐标系中的裁剪区域
        let scale = 1.0 / zoomScale
        
        // 计算在imageView坐标系中的裁剪区域
        var cropRect = CGRect.zero
        cropRect.origin.x = (scrollView.contentOffset.x + scrollView.contentInset.left) * scale
        cropRect.origin.y = (scrollView.contentOffset.y + scrollView.contentInset.top) * scale
        cropRect.size.width = cropBoxFrame.width * scale
        cropRect.size.height = cropBoxFrame.height * scale
        
        // 确保裁剪区域在图片范围内
        cropRect.origin.x = max(0, cropRect.origin.x)
        cropRect.origin.y = max(0, cropRect.origin.y)
        cropRect.size.width = min(currentImage.size.width - cropRect.origin.x, cropRect.size.width)
        cropRect.size.height = min(currentImage.size.height - cropRect.origin.y, cropRect.size.height)
        
        // 如果裁剪区域无效，返回nil
        if cropRect.width <= 0 || cropRect.height <= 0 {
            return nil
        }
        
        // 从当前图片中裁剪
        guard let cgImage = currentImage.cgImage?.cropping(to: cropRect) else { return nil }
        
        return UIImage(cgImage: cgImage, scale: currentImage.scale, orientation: currentImage.imageOrientation)
    }
}

// MARK: - UIScrollViewDelegate

extension ImageCropViewController {
    
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        updateImageViewFrameAndContentSize()
        adjustContentOffsetToValidArea()
    }
    
    func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
        adjustContentOffsetToValidArea()
    }
    
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
            adjustContentOffsetToValidArea()
        }
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        adjustContentOffsetToValidArea()
    }
}

// MARK: - OverlayView

private class OverlayView: UIView {
    
    var cropBoxFrame: CGRect = .zero {
        didSet {
            setNeedsDisplay()
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupView()
    }
    
    private func setupView() {
        backgroundColor = .clear
        isOpaque = false
        isUserInteractionEnabled = false
    }
    
    override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else { return }
        
        // 绘制半透明覆盖层
        UIColor.black.withAlphaComponent(0.5).setFill()
        context.fill(rect)
        
        // 清除裁剪框区域
        context.setBlendMode(.clear)
        context.fill(cropBoxFrame)
        context.setBlendMode(.normal)
        
        // 绘制裁剪框边框
        UIColor.white.setStroke()
        context.setLineWidth(2.0)
        context.stroke(cropBoxFrame)
        
        // 绘制网格线
        UIColor.white.withAlphaComponent(0.3).setStroke()
        context.setLineWidth(1.0)
        
        let thirdWidth = cropBoxFrame.width / 3
        let thirdHeight = cropBoxFrame.height / 3
        
        // 垂直线
        for i in 1...2 {
            let x = cropBoxFrame.minX + thirdWidth * CGFloat(i)
            context.move(to: CGPoint(x: x, y: cropBoxFrame.minY))
            context.addLine(to: CGPoint(x: x, y: cropBoxFrame.maxY))
        }
        
        // 水平线
        for i in 1...2 {
            let y = cropBoxFrame.minY + thirdHeight * CGFloat(i)
            context.move(to: CGPoint(x: cropBoxFrame.minX, y: y))
            context.addLine(to: CGPoint(x: cropBoxFrame.maxX, y: y))
        }
        
        context.strokePath()
    }
}

// MARK: - UIImage Extension for Transformations

extension UIImage {
    
    func rotated(by degrees: CGFloat) -> UIImage? {
        let radians = degrees * .pi / 180
        
        // 计算旋转后的尺寸
        var rotatedRect = CGRect(origin: .zero, size: self.size)
            .applying(CGAffineTransform(rotationAngle: radians))
        rotatedRect.origin = .zero
        
        let format = UIGraphicsImageRendererFormat()
        format.scale = self.scale
        format.opaque = false
        
        let renderer = UIGraphicsImageRenderer(size: rotatedRect.size, format: format)
        
        let rotatedImage = renderer.image { context in
            // 移动到中心
            context.cgContext.translateBy(x: rotatedRect.width / 2, y: rotatedRect.height / 2)
            // 旋转
            context.cgContext.rotate(by: radians)
            // 绘制图片
            let drawRect = CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height)
            self.draw(in: drawRect)
        }
        
        return rotatedImage
    }
    
    func flippedHorizontally() -> UIImage? {
        let format = UIGraphicsImageRendererFormat()
        format.scale = self.scale
        format.opaque = false
        
        let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
        
        let flippedImage = renderer.image { context in
            // 应用水平翻转
            context.cgContext.translateBy(x: self.size.width, y: 0)
            context.cgContext.scaleBy(x: -1, y: 1)
            
            self.draw(in: CGRect(origin: .zero, size: self.size))
        }
        
        return flippedImage
    }
    
    func flippedVertically() -> UIImage? {
        let format = UIGraphicsImageRendererFormat()
        format.scale = self.scale
        format.opaque = false
        
        let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
        
        let flippedImage = renderer.image { context in
            // 应用垂直翻转
            context.cgContext.translateBy(x: 0, y: self.size.height)
            context.cgContext.scaleBy(x: 1, y: -1)
            
            self.draw(in: CGRect(origin: .zero, size: self.size))
        }
        
        return flippedImage
    }
}
